#include "SerialPort.h"
#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <chrono>
#include <fstream>
#include <cstdint> // Explicitly include for uintX_t types

void onDataReceived(const uint8_t* data, size_t size)
{
    std::cout << "Received " << size << " bytes: ";
    std::cout.write(reinterpret_cast<const char*>(data), size);
    std::cout << std::endl;
    // // 打印接收到的数据 (以十六进制形式)
    // for (size_t i = 0; i < size; ++i) {
    //     std::cout << std::hex << (int)data[i] << " ";
    // }
    // std::cout << std::dec << std::endl;
}

inline uint64_t posix_time_ns_uint64()
{
    auto now = std::chrono::system_clock::now();
    return std::chrono::time_point_cast<std::chrono::nanoseconds>(now).time_since_epoch().count();
}

int main() {
    SerialPort serial;

    std::cout << "step1. Searching for available serial ports..." << std::endl;
    auto ports = SerialPort::listAvailablePorts();
    if (ports.empty()) {
        std::cout << "No serial ports found." << std::endl;
        return 1;
    }

    std::cout << "Available ports:" << std::endl;
    int32_t list_no = 0;
    for (const auto& port : ports) {
        list_no++;
        std::cout << list_no << "- " << port.port << " (" << port.description << ")" << std::endl;
    }

    int choice;
    std::string selectedPort;
    std::cout << "Enter the number of the port to open (ensure it's not in use by other applications): ";
    std::cin >> choice;
    getchar();

    if (choice > 0 && choice <= ports.size()) {
        selectedPort = ports[choice - 1].port;
    } else {
        std::cerr << "Invalid choice." << std::endl;
        return 1;
    }

    PortParam param{};
    param.portName = selectedPort;
    param.baudRate = Baudrate::BAUDRATE_921600;
    param.dataBits = DataBit::DATABIT_8;
    param.parity = Parity::NONE;
    param.stopBits = StopBits::ONE;

    std::cout << "step2. Opening port: " << selectedPort << std::endl;
    auto start_time = posix_time_ns_uint64();
    auto result = serial.openPort(param);
    auto end_time = posix_time_ns_uint64();
    std::cout << "use time : " << end_time - start_time << std::endl;
    if (!result) {
        uint64_t sent, received;
        std::string error;
        serial.getStatus(sent, received, error);
        std::cerr << "Failed to open port: " << error << std::endl;
        return 1;
    }
    std::cout << "Port opened successfully." << std::endl;

    // Give a small delay before opening the port
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    if (!serial.enableReceive(onDataReceived)) {
        std::cerr << "Failed to enable receiving." << std::endl;
        serial.closePort();
        return 1;
    }

    bool running = true;
    std::thread transmitThread([&serial, &running]()
    {
       int32_t cnt = 0;
       std::string data = "Testing data No: ";
       while (running)
       {
           std::string msg = data + std::to_string(cnt);
           serial.serialTransmit(reinterpret_cast<const uint8_t*>(msg.data()), static_cast<int32_t>(msg.size()));
           cnt++;
           std::this_thread::sleep_for(std::chrono::milliseconds(100));
       }
    });

    getchar();
    running = false;

    uint64_t bytesSent, bytesReceived;
    std::string errorInfo;
    serial.getStatus(bytesSent, bytesReceived, errorInfo);
    std::cout << "Total bytes sent: " << bytesSent << std::endl;
    std::cout << "Total bytes received: " << bytesReceived << std::endl;
    if (!errorInfo.empty()) {
        std::cout << "Last error: " << errorInfo << std::endl;
    } else {
        std::cout << "No recent errors." << std::endl;
    }

    std::cout << "step7. Closing port..." << std::endl;
    serial.closePort();
    std::cout << "Port closed." << std::endl;

    if (transmitThread.joinable())
        transmitThread.join();

    return 0;
}
